Repository navigation
fix(persistence): recover transient save refusals without edits - #470
Merged
Merged
Conversation
Deploying podnotes with
|
| Latest commit: |
fa7afc0
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://85a52177.podnotes.pages.dev |
| Branch Preview URL: | https://fix-save-refusal-recovery.podnotes.pages.dev |
chhoumann
added a commit
that referenced
this pull request
Oct 14, 2026
… of the full player (#472) * refactor(feeds): drop the ignored FeedRepository cache option Feeds are always cached since #468. The constructor still accepted a cache option that nothing read, and eight view tests still passed it. * refactor(player): move Next in queue into PlayerController.playNext The headset's Next in queue read the queue store and called play inline in bindMediaSession. PlayerController now owns it, beside play and the natural end's queue advance. * fix(settings): say an import that could not save yet saves by itself Since #470, PodNotes saves on its own once it can write data.json again. The Notice after an import whose final save failed still told the user to change a setting to save again. * refactor(ui): co-locate each component's styles and split Deck and Panel out of Player PodcastView.svelte held 1,300 lines of page and component CSS in one global block. Each component now carries its own styles, anchored on its own root class with the `.root :global {}` pattern the shell already used. The shell keeps its tokens, its layout, the Obsidian DOM rules and the classes several components share. Player.svelte loses the deck (title, scrubber, transport, capture bar) to Deck.svelte, and ChaptersPanel and UpNextPanel share their chrome through Panel.svelte. Cover draws a local file's tile, and SearchField takes the first run's large variant, so no page reaches into them for it. Variants of the shared .pn-iconbtn and .pn-btn classes win by specificity instead of by stylesheet order. * test(player): format the playNext tests * feat(ui): move between the wide player's tabs with arrow keys The Chapters and Up next tabs follow the ARIA tabs pattern: Left and Right move focus to the previous or next tab and wrap, Home and End go to the first and last, and the focused tab shows its panel. Only the selected tab is in the Tab order. * fix(ui): hide the fullscreen button in fullscreen and let play respect reduced motion In fullscreen the video frame's fullscreen button stayed visible and did nothing. It now hides there; Escape leaves fullscreen. The play button's 120 ms press transition ran even when the system asks for reduced motion. It now presses without a transition then. * refactor(verify): split screens.mjs by concern screens.mjs grew past 1,100 lines. It keeps its usage header, the verb dispatch and set; the instance calls, the seeded scenes and the contact sheet move to screens/instance.mjs, screens/scenes.mjs and screens/sheet.mjs. The code moved verbatim apart from imports, exports and the paths that moved one directory down. * refactor(ui): keep each button's touch cascade and move queue rows into EpisodeRow On a touch device Obsidian adds .mobile-tap to a tapped button, and its button:not(.clickable-icon).mobile-tap rule paints a fill. Search results, playlist rows, chapter rows and Up next's Edit button keep the specificity that resisted it, and the mini player's open button and the rail's add button keep the plain scoped rules that let it through. Queue rows are an EpisodeRow variant (queue, dragging) instead of rules QueueList laid over EpisodeRow and Cover. Deck no longer takes `wide`: the player passes no onchapters when the chapter name cannot open a panel. .pn-alt moves whole into AddPodcastPage, and the shell's head and back button rules move from the shared block to its layout.
This was referenced Oct 15, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Recover automatically from runtime data.json read failures, including an idle library whose unreadable file is moved away. Imports, key selections, and visibility flushes can read through a recovered outage immediately. Older and newer schemas stop retries and show one actionable Notice. Startup failures tell users to restore access and restart, and prevent defaults from overwriting the unread file.
DataFileWriternow owns refusal policy. The existing queue, merge, lineage, write readback, and shutdown barrier remain in place. Scope is persistence wiring and regression tests.Fixes #429
Fixes #430
Fixes #431
Fixes #432
Verification
npm run lint,npm run format:check,npm run typecheck,npm run build,npm run test, finalnpm run test:unit(2,540 tests),npm run test:tooling(13 tests), andnpm run docs:buildpass.npm run count:writesrecords 3 completed writes and no extra idle writes on both master and this branch.npm run sizereports 98,452 gzip bytes, up 269, below the 100,000-byte limit. Raw size is 311,304 bytes, up 529.Before/after evidence, disk hashes, exact commands and review record. Raw logs and review reports.
Wrong alternatives tested: all 14 fail
reads and writes nothing before a file was loaded, even when flushed or unloadedretries a refused read 10 s after the last attempt, also with edits, and writes once it readswrites the library again when its recovery write failsstops for a schema it must not write: no checkpoint, read or write until the next instancewrites the library once when the file reads as missing again, even without an edit#432 asks for readable startup data and a reload without writing defaultskeeps refusing before a file was loaded when the file is missing, empty or unreadablestarts no recovery write when the window unloads during its read#429 stops periodic reads for schema 99 and reports the required action onceretries a file with an invalid schema version until it reads, then writes the library oncereplaces startup protection with a schema stop and reads no furtherThe first timer mutation exposed a weak assertion. Moving that assertion before the strict save made the test catch it. Mutation commands and results include the failing tests for the first 13 variants. Startup-to-schema-stop mutation and failure.
QuickAdd prior art
Retains the queue, three-way merge, main-window timers, and unload protection from QuickAdd commits
d418f01f,46753e48,40dd5b4f, and0142db3d. QuickAdd has no refusal policy and normalizes unreadable data to defaults. PodNotes needs explicit startup protection, runtime recovery work, and schema stops to avoid overwriting its library or credentials.Release impact
No schema, settings shape, public API, or URI change. A missing or empty file no longer unlocks an instance that started with unreadable data. A valid synced library can still be adopted safely. Runtime schema refusals require a new instance after restart or update. Shutdown still starts no new writes, so an idle recovery needs to finish before the user quits.
Docs at release
Update
/save-problems/in held PR #458:Follow-up outside the permitted UI scope: remove the stale "Change any setting to save again" sentence from the import rollback failure Notice.
Note
Recover transient data-file read refusals without losing pending edits
DataFileWriterin writer.ts around a newReadOutcomeunion. Retryable read refusals (unreadable, invalid, or missing data) now stop writes but keep retrying reads at the checkpoint interval; once a read succeeds, the writer merges, recreates a missing file, and writes pending or recovered data.PodNotesin main.ts delegates refusal decisions to the writer. Startup with an unreadable existing file now initializes in-memory defaults, refuses persistence, and directs the user to restore read access and reload.flushSavescan perform a recovery read and write instead of blanket-skipping.retryPendingAPI and the old four-state write-refusal type; close-time refusals remain explicit.PodNotes.saveSettingsStrictnow rejects with writer-reported refusal errors; refusal Notices are replaced on new reasons and removed on recovery; external changes during an outage no longer drop the loaded library. Checkpersistence.Refusal,persistence.ReadOutcome, andPodNotes.dataFileAccessfor the new contracts.Macroscope summarized fa7afc0.